<?php
/**
*
* @package YubiKey Login
* @version 1.0.3
* @copyright (c) 2010 Tim Schlueter
* @license http://opensource.org/licenses/gpl-license.php GNU Public License 
*
*/

/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
	exit;
}

/**
 * @package acp
 */
class acp_yubikey_login
{
	var $u_action;
	var $new_config = array();

	function main($id, $mode)
	{
		global $db, $user, $template;
		global $config, $phpbb_root_path, $phpEx;

		$user->add_lang('mods/yubikey_login');

		/**
		*	Validation types are:
		*	string, int, bool,
		*	script_path (absolute path in url - beginning with / and no trailing slash),
		*	rpath (relative), rwpath (realtive, writable), path (relative path, but able to escape the root), wpath (writable)
		*/
		switch ($mode)
		{
			case 'yubikey_login_settings':
				$display_vars = array(
					'title'	=> 'ACP_YUBIKEY_SETTINGS',
					'vars'	=> array(
						'legend1'			=> 'GENERAL_SETTINGS',
						'allow_yubikey_login'		=> array('lang' => 'FORM_YUBIKEY_LOGIN',	'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),
						'yubikey_login_method'		=> array('lang' => 'FORM_YUBIKEY_LOGIN_METHOD',	'validate' => 'string',	'type' => 'custom',	'method' => 'select_yubikey_login_method',	'params' => array('{CONFIG_VALUE}'),	'explain' => false),
						'yubikey_login_optional'	=> array('lang' => 'FORM_YUBIKEY_LOGIN_OPTIONAL',	'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),

						'legend2'			=> 'ACP_YUBIKEY_VAL_SER_URLS',
						'yubikey_val_ser_type'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_TYPE',	'validate' => 'bool',	'type' => 'custom', 'method' => 'select_yubikey_val_ser_type', 'explain' => false),
						'yubikey_val_ser_url1'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_URL1',	'validate' => 'string',	'type' => 'text:50:50', 'explain' => false),
						'yubikey_val_ser_url2'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_URL2',	'validate' => 'string',	'type' => 'text:50:50', 'explain' => false),
						'yubikey_val_ser_url3'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_URL3',	'validate' => 'string',	'type' => 'text:50:50', 'explain' => false),
						'yubikey_val_ser_url4'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_URL4',	'validate' => 'string',	'type' => 'text:50:50', 'explain' => false),
						'yubikey_val_ser_url5'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_URL5',	'validate' => 'string',	'type' => 'text:50:50', 'explain' => false),

						'legend3'			=> 'ACP_YUBIKEY_VAL_SER_PARAMS',
						'yubico_api_id'			=> array('lang' => 'FORM_YUBIKEY_VAL_SER_API_ID',	'validate' => 'int:0',	'type' => 'text:5:5', 'explain' => true),
						'yubico_api_key'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_API_KEY',	'validate' => 'string',	'type' => 'text:31:30', 'explain' => true),
						'yubico_api_timeout'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_API_TIMEOUT',	'validate' => 'int:0',	'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
						'yubico_api_https'		=> array('lang' => 'FORM_YUBIKEY_VAL_SER_API_HTTPS',	'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),
					)
				);
				$this->yubikey_settings($display_vars);
			break;
			
			case 'yubikey_login_devices':
				$this->yubikey_devices();
			break;
			
			default:
				trigger_error('NO_MODE', E_USER_ERROR);
			break;
		}
	}
	
	function yubikey_settings($display_vars)
	{
		global $user, $template, $config;
		
		$submit = (isset($_POST['submit'])) ? true : false;

		$form_key = 'acp_yubikey';
		add_form_key($form_key);
		
		if (isset($display_vars['lang']))
		{
			$user->add_lang($display_vars['lang']);
		}

		$this->new_config = $config;
		$cfg_array = (isset($_POST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_config;
		$error = array();

		// We validate the complete config if whished
		validate_config_vars($display_vars['vars'], $cfg_array, $error);

		if ($submit && !check_form_key($form_key))
		{
			$error[] = $user->lang['FORM_INVALID'];
		}
		// Do not write values if there is an error
		if (sizeof($error))
		{
			$submit = false;
		}

		// We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to...
		foreach ($display_vars['vars'] as $config_name => $null)
		{
			if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false)
			{
				continue;
			}

			$this->new_config[$config_name] = $config_value = $cfg_array[$config_name];

			if ($submit)
			{
				set_config($config_name, $config_value);
			}
		}

		if ($submit)
		{
			// Log the action
			add_log('admin', 'LOG_YUBIKEY_SETTINGS_SAVED');

			trigger_error($user->lang['YUBIKEY_SETTINGS_SAVED'] . adm_back_link($this->u_action));
		}

		// Set up the page
		$this->tpl_name = 'acp_board';
		$this->page_title = $display_vars['title'];

		$template->assign_vars(array(
			'L_TITLE'		=> $user->lang[$display_vars['title']],
			'L_TITLE_EXPLAIN'	=> $user->lang[$display_vars['title'] . '_EXPLAIN'],

			'S_ERROR'		=> (sizeof($error)) ? true : false,
			'ERROR_MSG'		=> implode('<br />', $error),

			'U_ACTION'		=> $this->u_action)
		);

		$contents_count = sizeof($display_vars['vars']);
		$i = 0;

		// Output relevant page
		foreach ($display_vars['vars'] as $config_key => $vars)
		{
			$i = $i + 1;

			if (!is_array($vars) && strpos($config_key, 'legend') === false)
			{
				continue;
			}

			if (strpos($config_key, 'legend') !== false)
			{
				$template->assign_block_vars('options', array(
					'S_LEGEND'	=> true,
					'LEGEND'	=> (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars)
				);

				continue;
			}

			$type = explode(':', $vars['type']);

			$l_explain = '';
			if ($vars['explain'] && isset($vars['lang_explain']))
			{
				$l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain'];
			}
			else if ($vars['explain'])
			{
				$l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : '';
			}

			$content = build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars);

			if (empty($content))
			{
				continue;
			}

			if($i == $contents_count)
			{
				// Last element. Append javascript code
				$content .= "<script type='text/javascript'>";
				
				$content .= "function edYkOptional(){var x = document.getElementById('yubikey_login_method');var disable = false;if(x.options[x.selectedIndex].value != 'UN-PWD-YK'){disable=true;}var e = document.getElementsByName('config[yubikey_login_optional]');for(var i = 0; i < e.length; i++){e[i].disabled=disable;}}";

				$content .= "function edYkURLs(){var x = document.getElementById('yubikey_val_ser_type');var disable = x.checked;for(var i = 1; i <= 5; i++){var e = document.getElementById('yubikey_val_ser_url' + i);e.disabled=disable;}}";

				$content .= "window.onload = function(){edYkOptional();edYkURLs();document.getElementById('yubikey_login_method').onchange = function(){edYkOptional();};var e = document.getElementsByName('config[yubikey_val_ser_type]');for(var i = 0; i < e.length; i++){e[i].onclick = function(){edYkURLs();};}}";

				$content .= "</script>";
			}

			$template->assign_block_vars('options', array(
				'KEY'			=> $config_key,
				'TITLE'			=> (isset($user->lang[$vars['lang']])) ? $user->lang[$vars['lang']] : $vars['lang'],
				'S_EXPLAIN'		=> $vars['explain'],
				'TITLE_EXPLAIN'		=> $l_explain,
				'CONTENT'		=> $content,
				)
			);

			unset($display_vars['vars'][$config_key]);
		}
	}
	
	function yubikey_devices()
	{
		global $db, $user, $template, $config, $phpbb_root_path, $phpEx;

		include "{$phpbb_root_path}includes/functions_yubikey.$phpEx";

		$action = isset($_GET['action']) ? request_var('action', '') : false;
		$submit = request_var('submit', '');
		$deviceid = request_var('device', '0');
		$search_option = request_var('search_options', '0');
		$search_for = request_var('search_for', '');
		$start = request_var('start', 0);

		$keys_per_page = 25;

		if($submit == $user->lang['SEARCH'])
		{
			$action = 'search';
		}

		$error = array();

		$form_key = 'acp_yubikeys';
		add_form_key($form_key);

		if ($action == 'search' && !check_form_key($form_key))
		{
			$error[] = $user->lang['FORM_INVALID'];
		}
		
		// Perform the requested action
		if($action && $deviceid != '0')
		{
			switch ($action)
			{
				case 'activate':
					activate_deactivate_yubikey($deviceid, YUBIKEY_ACTIVE, ($this->u_action) ? $this->u_action : null, true, true);
				break;

				case 'deactivate':
					activate_deactivate_yubikey($deviceid, YUBIKEY_INACTIVE, ($this->u_action) ? $this->u_action : null, true, true);
				break;

				case 'delete':
					delete_yubikey($deviceid, ($this->u_action) ? $this->u_action : null, true, true);
				break;
			}
		}
		
		// Get YubiKeys to display
		$yubikeys_exist = false;
		$sql  = ' SELECT ut.user_id, ut.username, yt.deviceid, yt.lastseen, yt.status';
		$sql .= ' FROM ' . USERS_TABLE . ' ut INNER JOIN ' . YUBIKEY_TABLE . ' yt ON ut.user_id = yt.user_id';
		if($action == 'search')
		{
			$yubikeys_exist = true; // just to hide the no yubikeys to any message while seraching
			if(!empty($search_for))
			{
				if($search_option == '1')
				{
					// search for deviceid
					$sql .= ' WHERE deviceid = \'' . $db->sql_escape($search_for) . '\'';
				}
				else
				{
					// search for username
					$sql .= ' WHERE username_clean = \'' . $db->sql_escape(utf8_clean_string($search_for)) . '\'';
				}
			}
		}
		$result = $db->sql_query_limit($sql, $keys_per_page, $start);
	
		while ($row = $db->sql_fetchrow($result))
		{
			$yubikeys_exist = true;

			$lastlogin = $row['lastseen'];
			if ($lastlogin == 0)
			{
				$lastlogin = $user->lang['NEVER'];
			}
			elseif (time() - $lastlogin < 86400)
			{
				$lastlogin = date("g:i a", $lastlogin);
			}
			else
			{
				$lastlogin = date("F j, Y", $lastlogin);
			}

			$active_lang = ($row['status'] == YUBIKEY_ACTIVE)? 'YUBIKEY_DEACTIVATE' : 'YUBIKEY_ACTIVATE';
			$active_value = ($row['status'] == YUBIKEY_ACTIVE) ? 'deactivate' : 'activate';

			$template->assign_block_vars('yubikey', array(
				'USER_NAME'		=> $row['username'],
				'DEVICE_ID'		=> $row['deviceid'],
				'LASTLOGIN'		=> $lastlogin,
				'STATUS'		=> ($row['status'] == YUBIKEY_ACTIVE)? "Active": "Inactive",
				'U_ACTIVATE_DEACTIVATE'	=> append_sid("{$this->u_action}&amp;action=$active_value&amp;device={$row['deviceid']}"),
				'L_ACTIVATE_DEACTIVATE'	=> $user->lang[$active_lang],
				'U_DELETE'		=> append_sid("{$this->u_action}&amp;action=delete&amp;device={$row['deviceid']}"),
			));
		}
		$db->sql_freeresult($result);

		$sql  = ' SELECT COUNT(ut.user_id) AS total_entries';
		$sql .= ' FROM ' . USERS_TABLE . ' ut INNER JOIN ' . YUBIKEY_TABLE . ' yt ON ut.user_id = yt.user_id';

        	$result = $db->sql_query($sql);
	        $yubikeys_count = (int) $db->sql_fetchfield('total_entries');
        	$db->sql_freeresult($result);

		$search_options = '';
		$search_options .= '<option value="0"' . (($search_option == '0')?' selected="selected"':'') . '>' . $user->lang['USERNAME'] . '</option>';
		$search_options .= '<option value="1"' . (($search_option == '1')?' selected="selected"':'') . '>' . $user->lang['YUBIKEY_DEVICE_ID'] . '</option>';

		// Set up the page
		$this->tpl_name = 'acp_yubikeys';
		$this->page_title = $user->lang['ACP_YUBIKEYS'];
		
		$template->assign_vars(array(
			'L_TITLE'			=> $user->lang['ACP_YUBIKEYS'],
			'L_TITLE_EXPLAIN'		=> $user->lang['ACP_YUBIKEYS_EXPLAIN'],

			'S_ERROR'			=> (sizeof($error)) ? true : false,
			'ERROR_MSG'			=> implode('<br />', $error),

			'S_YUBIKEYS_EXIST'		=> $yubikeys_exist,

			'U_SEARCH'			=> append_sid("{$this->u_action}&amp;action=search"),
			'S_YUBIKEY_SEARCH_OPTIONS'	=> $search_options,
			'S_YUBIKEY_SEARCH_FOR'		=> $search_for,

			'S_ON_PAGE'			=> on_page($yubikeys_count, $keys_per_page, $start),
			'PAGINATION'			=> generate_pagination($this->u_action, $yubikeys_count, $keys_per_page, $start, true),
		));
	}

	/**
	* Generate a list of YubiKey login methods
	*/
	function select_yubikey_login_method($selected_method = '')
	{
		global $user;
		$login_methods = array(0 => 'PWD-YK', 1 => 'UN-OR-YK-PWD', 2 => 'YK-ONLY', 3 => 'UN-PWD-YK');

		$s_yubikey_login_method = '<select name="config[yubikey_login_method]" id="yubikey_login_method">';

		foreach ($login_methods as $method)
		{
			$s_yubikey_login_method .= '<option value="' . $method . '"' . (($selected_method == $method) ? ' selected="selected"' : '') . '>' . $user->lang['YUBIKEY_LOGIN_METHOD_' . str_replace('-', '_', $method)] . '</option>';
		}

		$s_yubikey_login_method .= '</select>';
		return $s_yubikey_login_method;
	}

	/**
	* Select validation service type
	*/
	function select_yubikey_val_ser_type($value, $key)
	{
		$radio_ary = array(0 => 'YUBIKEY_VAL_SER_TYPE_ONLINE', 1 => 'YUBIKEY_VAL_SER_TYPE_CUSTOM');

		return h_radio('config[yubikey_val_ser_type]', $radio_ary, $value, $key);
	}
}

?>
